﻿using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using SoulDoorEngine.Framework;
using SoulDoorEngine.Framework.Components;
using SoulDoorEngine.Framework.Services;
using SoulDoorEngine.Framework.Utilities;
using SoulDoorEngine.Components;
using SoulDoorEngine.Framework.Screens;
using SoulDoorEngine.Components.Cameras;

namespace SoulDoorEngine.Components.Scene
{
    public class Actor : Component, I3DComponent
    {
        // The model to draw
        Model model;
        Dictionary<ModelMeshPart, string> Materials = new Dictionary<ModelMeshPart, string>();
        //0.25.4.3打包后更改 2011.12.15
        private string _Model;

        /// <summary>
        /// 模型文件名
        /// </summary>
        public string Model
        {
            ////0.25.4.3打包后更改 2011.12.15
            get { return _Model; }
            set
            {
                _Model = value;
                model = Engine.Content.Load<Model>(value);

                Materials.Clear();

                foreach (ModelMesh mesh in model.Meshes)
                {
                    foreach (ModelMeshPart part in mesh.MeshParts)
                    {
                        TexturedMaterial mat = new TexturedMaterial(this.Parent);

                        if (part.Tag != null)
                        {
                            string texName = (string)part.Tag;
                            mat.TextureName = "Content/" + texName;
                        }

                        Materials.Add(part, mat.Name);
                        //materials.Add(part, new MeshPartMaterial().CreateFromMeshPart(part));//教程版本
                    }
                }
            }
        }

        // I3DComponent values
        public virtual Vector3 Position { get; set; }
        public Vector3 EulerRotation
        {
            get { return MathUtil.MatrixToVector3(Rotation); }
            set { Rotation = MathUtil.Vector3ToMatrix(value); }
        }
        public virtual Matrix Rotation { get; set; }
        public virtual Vector3 Scale { get; set; }
        public virtual BoundingBox BoundingBox
        {
            get
            {
                return new BoundingBox(
                    Position - (Scale / 2),
                    Position + (Scale / 2)
                );
            }
        }

        // Constructors take a model to draw and a position
        public Actor(string Model, Vector3 Position)
            : base()
        {
            Setup(Model, Position);
        }

        public Actor(string Model, Vector3 Position, Screen Parent)
            : base(Parent)
        {
            Setup(Model, Position);
        }

        // Provide a method to setup the actor so we don't need to 
        // write it in each constructor
        //0.25.4.3打包后更改 2011.12.15
        void Setup(string Model, Vector3 Position)
        {
            this.Model = Model;
            this.Position = Position;
            Scale = Vector3.One;
            EulerRotation = Vector3.Zero;
        }

        public override void Draw()
        {
            // Look for a camera in the service container
            Camera camera = Engine.Services.GetService<Camera>();

            // Throw an exception if one isn't present
            if (camera == null)
            {
                throw new System.Exception("Camera not found in engine's"
                + "service container, cannot draw");
            }

            //***************************************************************
            //*******SoulDoorEngine0.25.3.1x打包后更改顺序*********************
            //***************************************************************
            Matrix[] transforms = new Matrix[model.Bones.Count];
            model.CopyAbsoluteBoneTransformsTo(transforms);

            // Generate the world matrix (describes the objects movement in 3D)
            Matrix world = MathUtil.CreateWorldMatrix(Position, Rotation, Scale);
            
            Engine.GraphicsDevice.BlendState = BlendState.AlphaBlend;
            Engine.GraphicsDevice.DepthStencilState = DepthStencilState.Default;

            // Loop through meshes and effects and set them up to draw
            //0.25.4.3打包后更改 2011.12.15
            foreach (ModelMesh mesh in model.Meshes)
            {
                foreach (ModelMeshPart part in mesh.MeshParts)
                {
                    TexturedMaterial material = (TexturedMaterial)Engine.Services.GetService<MaterialManager>().GetMaterial(Materials[part]);
                    material.Prepare3DDraw(world);
                    part.Effect = material.Effect;
                }

                // Draw the mesh
                mesh.Draw();
            }
        }
    }
}
